using System;
using System.Configuration;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Xml;

namespace Pitoshka.Web.UrlRewriter
{
    class RewriteModule : IHttpModule
    {
        private RewriteHelper rewriteHelper;

        private const string ItemOriginalUrl = "ItemOriginalUrl";
        private const string ItemClientQueryString = "ItemClientQueryString";
        private const string ItemCachedPathAfterRewrite = "ItemCachedPathAfterRewrite";

        private List<KeyValuePair<Regex, string>> regexes = new List<KeyValuePair<Regex,string>>();

        

        public RewriteModule()
        {
            this.rewriteHelper = new RewriteHelper();

            RewriteModuleSectionHandler cfg = (RewriteModuleSectionHandler)ConfigurationManager.GetSection("modulesSection/rewriteModule");

            XmlNode rules = cfg.XmlSection.SelectSingleNode("rewriteRules");
            foreach (XmlNode xml in rules.SelectNodes("rule"))
            {
                regexes.Add(new KeyValuePair<Regex, string>(
                    new Regex(cfg.RewriteBase + xml.SelectSingleNode("LookFor").InnerText, RegexOptions.IgnoreCase | RegexOptions.Compiled),
                    xml.SelectSingleNode("SendTo").InnerText
                ));
            }
        }
        public void Dispose() { }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(RewriteModule_BeginRequest);
            context.PreRequestHandlerExecute += new EventHandler(RewriteModule_PreRequestHandlerExecute);
            context.PostRequestHandlerExecute += new EventHandler(RewriteModule_PostRequestHandlerExecute);
        }

        void RewriteModule_BeginRequest(object sender, EventArgs e)
        {
            RewriteModuleSectionHandler cfg = (RewriteModuleSectionHandler)ConfigurationManager.GetSection("modulesSection/rewriteModule");

            string path = HttpContext.Current.Request.Path;
            if (path.Length == 0) return; // we have nothing to process
			string fileName = HttpContext.Current.Server.MapPath(path);
			if (File.Exists(fileName)) 
				return;


            string LastPartOfUrl = (path.IndexOf("/") != -1) ? path.Substring(path.LastIndexOf("/")) : path;
            if (LastPartOfUrl.LastIndexOf(".") < 0 && path.Substring(path.Length - 1) != "/")
            {
                //HttpContext.Current.Response.StatusCode = 302;
                HttpContext.Current.Response.Redirect(path + "/", true);
            }


            foreach (KeyValuePair<Regex, string> pair in regexes)
            {
                try
                {
                    Regex re = pair.Key;
                    Match match = re.Match(path);
                    if (match.Success)
                    {
                        path = re.Replace(path, pair.Value);
                        if (path.Length != 0)
                        {
                            string destinationUrl = cfg.RewriteBase + path;

                            // save original path to context
                            HttpContext.Current.Items.Add(ItemOriginalUrl, HttpContext.Current.Request.RawUrl);

                            string requestQuerystring = string.Empty;
                            int pos = HttpContext.Current.Request.RawUrl.IndexOf('?');
                            if (pos >= 0)
                                requestQuerystring = HttpContext.Current.Request.RawUrl.Substring(pos + 1);

                            HttpContext.Current.Items[ItemClientQueryString] = requestQuerystring;

                            destinationUrl = rewriteHelper.JoinUrlParameter(rewriteHelper.HandleRootOperator(destinationUrl), requestQuerystring);
                            
                            
                            // rewrite
                            HttpContext.Current.RewritePath(destinationUrl, false);
                        }
                        return;
                    }
                }
                catch (Exception ex)
                {
                    throw (new Exception("Incorrect rule.", ex));
                }
            }
            return;
        }

        void RewriteModule_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            System.Web.UI.Page page = app.Context.CurrentHandler as System.Web.UI.Page;
            if (page != null)
            {
                page.PreInit += new EventHandler(OnPagePreInit);
            }
        }

        private void OnPagePreInit(object sender, EventArgs e)
        {
            HttpContext context = HttpContext.Current;
            string virtualUrl = (string)HttpContext.Current.Items[ItemOriginalUrl];

            if (!string.IsNullOrEmpty(virtualUrl))
            {
                if (virtualUrl.IndexOf('?') >= 0)
                    virtualUrl = virtualUrl.Substring(0, virtualUrl.IndexOf('?'));

                string clientQueryString = (string) HttpContext.Current.Items[ItemClientQueryString];

                string fullQueryString = context.Request.QueryString.ToString();
                HttpContext.Current.Items.Add(ItemCachedPathAfterRewrite, context.Request.Path + "?" + fullQueryString);

                context.RewritePath(virtualUrl, string.Empty, clientQueryString, true);

                Page page = sender as Page;
                clientQueryString = page.ClientQueryString;

                context.RewritePath(virtualUrl, string.Empty, fullQueryString, true);
            }
        }

        void RewriteModule_PostRequestHandlerExecute(object sender, EventArgs e)
        {
            HttpApplication context = sender as HttpApplication;
            string cachedPath = (string)context.Context.Items[ItemCachedPathAfterRewrite];
            if (!string.IsNullOrEmpty(cachedPath))
            {
                context.Context.RewritePath(cachedPath);
            }
        }

    }
}
